/*
 *   Copyright (c) 2018. 刘路 All rights reserved
 *   版权所有 刘路 并保留所有权利 2018.
 *   ===============================================================
 *   这不是一个自由软件！您只能在不用于商业目的的前提下对程序代码进行修改和
 *   使用。不允许对程序代码以任何形式任何目的的再发布。如果项目发布携带作者
 *   认可的特殊 LICENSE 则按照 LICENSE 执行，废除上面内容。请保留原作者信息。
 *   ================================================================
 *   刘路（feedback@zhoyq.com）于 2018. 创建
 *   http://zhoyq.com
 */

package com.zhoyq.helper.prop;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.Properties;
import java.util.StringTokenizer;

/**
 * 增强版属性类 支持监视改变。 这个类扩展自Java基础的属性类，
 * 支持监视并且也支持更多类型转换。
 * @see PropertyMonitoring
 * @author 刘路
 */
public class ObservableProperties extends Properties {

  public Logger log = LoggerFactory.getLogger(ObservableProperties.class);

  PropertyMonitoring observers[];
  int observers_count;

  /**
   * 注册监控
   * @param o 实现监控接口的类
   *         {@link com.zhoyq.helper.prop.PropertyMonitoring}
   */
  public synchronized void registerObserver(PropertyMonitoring o) {
    // 试着寻找空的位置
    for (int i = 0; i < observers.length; i++) {
      if (observers[i] == null) {
        observers[i] = o;
        return;
      }
    }
    // 添加 有需要的话增长数组长度
    if (observers_count + 1 >= observers.length) {
      PropertyMonitoring m[] = new PropertyMonitoring[observers.length * 2];
      System.arraycopy(observers, 0, m, 0, observers.length);
      observers = m;
    }
    observers[observers_count++] = o;
  }

  /**
   * 取消注册监控
   * @param o 取消的监控类
   *          {@link com.zhoyq.helper.prop.PropertyMonitoring}
   * @return 如果成功取消返回true否则返回false
   */

  public synchronized boolean unregisterObserver(PropertyMonitoring o) {
    for (int i = 0; i < observers.length; i++) {
      if (observers[i] == o) {
        observers[i] = null;
        return true;
      }
    }
    return false;
  }

  /**
   * 更新一个属性值 如果属性值真的改变了 通知监控
   * @param name 属性名
   * @param value 属性值 空值代表取消属性
   * @return 如果成功改变返回true否则false
   */

  public synchronized boolean putValue(String name, String value) {
    log.debug(String.format("ObservableProperties: put %s=[%s]",name,value));
    // 如果值为空 直接去除
    if (value == null) {
      super.remove(name);
      return true;
    }
    // 要经过每一个 PropertyMonitoring 的监视
    String old = (String) get(name);
    if ((old == null) || (!old.equals(value))) {
      super.put(name, value);
      for (int i = 0; i < observers.length; i++) {
        if (observers[i] == null){
          continue;
        }
        log.debug(String.format("ObservableProperties: notifies %s",observers[i]));
        if (!observers[i].propertyChanged(name)) {
          if (old != null){
            super.put(name, old);
          }
          return false;
        }
      }
    }
    return true;
  }

  /**
   * 获取属性boolean值
   * @param name 属性名
   * @param def 默认值
   * @return 返回boolean值
   */

  public boolean getBoolean(String name, boolean def) {
    String v = getProperty(name, null);
    if (v != null){
      return "true".equalsIgnoreCase(v) ? true : false;
    }
    return def;
  }

  /**
   * 获取属性String值
   * @param name 属性名
   * @param def 默认值
   * @return 返回boolean值
   */
  public String getString(String name, String def) {
    String v = getProperty(name, null);
    if (v != null){
      return v;
    }
    return def;
  }

  /**
   * 获取属性String数组值 （字符串通过 <strong>|</strong> 分割的数组）
   * @param name 属性值
   * @param def 默认值
   * @return 字符串数组
   */

  public String[] getStringArray(String name, String def[]) {
    String v = getProperty(name, null);
    if (v == null){
      return def;
    }
    String ret[] = v.split("|");
    if(ret == null || ret.length == 0){
      return def;
    }
    return ret;
  }

  /**
   * 获取属性Integer值
   * 支持 0x 以及 # 开始的16进制数解析
   * @param name 属性值
   * @param def 默认值
   * @return Integer
   */
  public int getInteger(String name, int def) {
    String v = getProperty(name, null);
    if (v != null) {
      try {
        if (v.startsWith("0x")) {
          return Integer.valueOf(v.substring(2), 16).intValue();
        }
        if (v.startsWith("#")) {
          return Integer.valueOf(v.substring(1), 16).intValue();
        }
        return Integer.valueOf(v).intValue();
      } catch (NumberFormatException e) {
      }
    }
    return def;
  }
  /**
   * 获取属性Long值
   * @param name 属性值
   * @param def 默认值
   * @return Long
   */
  public long getLong(String name, long def) {
    String v = getProperty(name, null);
    if (v != null) {
      try {
        return Long.valueOf(v).longValue();
      } catch (NumberFormatException e) { }
    }
    return def;
  }

  /**
   * 获取属性double值
   * @param name 属性值
   * @param def 默认值
   * @return double
   */
  public double getDouble(String name, double def) {
    String v = getProperty(name, null);
    if (v != null) {
      try {
        return Double.valueOf(v).doubleValue();
      } catch (NumberFormatException ex) { }
    }
    return def;
  }

  /**
   * 获取属性File
   * @param name 属性值
   * @param def 默认值
   * @return File
   */
  public File getFile(String name, File def) {
    String v = getProperty(name, null);
    if (v != null){
      return new File(v);
    }
    return def;
  }

  /**
   * 初始化
   * @param props Properties类实现
   */
  public ObservableProperties(Properties props) {
    super(props);
    this.observers = new PropertyMonitoring[5];
    this.observers_count = 0;
  }

}
